#include <GameEngine/UnitTest/unit_test.h>

#include <GameEngine/Geometry/Topology/halfedge_trgl_mesh.h>
#include <GameEngine/Geometry/Location/point2d.h>

#include <vector>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif


//! Launch the unit tests on HalfEdgeMesh objects
/*!
 @return True if all unit tests on HalfEdgeMesh objects were
         succesful, false otherwise
 */
bool UnitTest::test_geometry_halfedge_trgl_mesh_functions() {
	bool res = true;

	// Get number of bytes
	MemoryManager::BytesCount bytes = MemoryManager::instance()->bytes();

	// Create HalfEdgeMesh
	GameEngine::HalfEdgeTrglMesh< GameEngine::Point2d<float>* > mesh;

	// Create vertices
	std::vector< GameEngine::Point2d<float> > pts;
	pts.push_back( GameEngine::Point2d<float>(0.00f,0.00f) );
	pts.push_back( GameEngine::Point2d<float>(1.00f,0.00f) );
	pts.push_back( GameEngine::Point2d<float>(1.00f,1.00f) );
	pts.push_back( GameEngine::Point2d<float>(0.00f,1.00f) );
	pts.push_back( GameEngine::Point2d<float>(0.50f,0.75f) );

	// Test add triangle
	GameEngine::HalfEdgeFace< GameEngine::Point2d<float>* >* f1 = mesh.add_triangle(&(pts[0]),&(pts[1]),&(pts[2]));
	{{
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test add_triangle()", ( f1 != nil ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test add_triangle()", ( mesh.vertex_count() == 3 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test add_triangle()", ( mesh.edge_count() == 6 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test add_triangle()", ( mesh.face_count() == 1 ) );
	}}

	// Test add triangle
	GameEngine::HalfEdgeFace< GameEngine::Point2d<float>* >* f2 = mesh.add_triangle(&(pts[2]),&(pts[3]),&(pts[0]));
	{{
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test add_triangle()", ( f2 != nil ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test add_triangle()", ( mesh.vertex_count() == 4 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test add_triangle()", ( mesh.edge_count() == 12 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test add_triangle()", ( mesh.face_count() == 2 ) );
	}}

	// Test connect triangles
	{{
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test connect()", ( mesh.connect(*f1,*f2) == true ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test connect()", ( mesh.vertex_count() == 4 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test connect()", ( mesh.edge_count() == 10 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test connect()", ( mesh.face_count() == 2 ) );
	}}

	// Test triangles adjacent to f1
	{{
		int border_face = 0, f2_face = 0, other_face = 0;
		bool first = true; 
		for ( GameEngine::HalfEdge< GameEngine::Point2d<float>* >* it = f1->edge(); ( ( first == true ) || ( it != f1->edge() ) ); it = it->next_edge() ) {
			first = false;
			if ( it->opposite_edge()->face() == nil ) {
				++border_face;
			}
			else if ( it->opposite_edge()->face() == f2 ) {
				++f2_face;
			}
			else {
				++other_face;
			}
		}
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test adjacency", ( border_face == 2 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test adjacency", ( f2_face == 1 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test adjacency", ( other_face == 0 ) );
	}}

	// Test triangles adjacent to f2
	{{
		int border_face = 0, f1_face = 0, other_face = 0;
		bool first = true; 
		for ( GameEngine::HalfEdge< GameEngine::Point2d<float>* >* it = f2->edge(); ( ( first == true ) || ( it != f2->edge() ) ); it = it->next_edge() ) {
			first = false;
			if ( it->opposite_edge()->face() == nil ) {
				++border_face;
			}
			else if ( it->opposite_edge()->face() == f1 ) {
				++f1_face;
			}
			else {
				++other_face;
			}
		}
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test adjacency", ( border_face == 2 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test adjacency", ( f1_face == 1 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test adjacency", ( other_face == 0 ) );
	}}

	// Test faces around vertices
	{{
		GameEngine::HalfEdgeVertex< GameEngine::Point2d<float>* >* v1 = mesh.find_vertex(&(pts[0]));
		std::list< GameEngine::HalfEdgeFace< GameEngine::Point2d<float>* >* > faces = v1->faces_around_vertex();
		int count = 0, f1_face = 0, f2_face = 0, other_face = 0;
		for ( std::list< GameEngine::HalfEdgeFace< GameEngine::Point2d<float>* >* >::iterator it = faces.begin(); it != faces.end(); ++it ) {
			if ( (*it) == f1 ) ++f1_face;
			else if ( (*it) == f2 ) ++f2_face;
			else ++other_face;
			++count;
		}
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test faces around vertices", ( count == 2 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test faces around vertices", ( f1_face == 1 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test faces around vertices", ( f2_face == 1 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test faces around vertices", ( other_face == 0 ) );
	}}

	// Test faces around vertices
	{{
		GameEngine::HalfEdgeVertex< GameEngine::Point2d<float>* >* v1 = mesh.find_vertex(&(pts[1]));
		std::list< GameEngine::HalfEdgeFace< GameEngine::Point2d<float>* >* > faces = v1->faces_around_vertex();
		int count = 0, f1_face = 0, f2_face = 0, other_face = 0;
		for ( std::list< GameEngine::HalfEdgeFace< GameEngine::Point2d<float>* >* >::iterator it = faces.begin(); it != faces.end(); ++it ) {
			if ( (*it) == f1 ) ++f1_face;
			else if ( (*it) == f2 ) ++f2_face;
			else ++other_face;
			++count;
		}
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test faces around vertices", ( count == 1 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test faces around vertices", ( f1_face == 1 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test faces around vertices", ( f2_face == 0 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test faces around vertices", ( other_face == 0 ) );
	}}

	// Test disconnect triangles
	{{
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test disconnect()", ( mesh.disconnect(*f1,*f2) == true ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test disconnect()", ( mesh.vertex_count() == 4 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test disconnect()", ( mesh.edge_count() == 12 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test disconnect()", ( mesh.face_count() == 2 ) );
	}}

	// Test insert vertex
	{{
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test connect()", ( mesh.connect(*f1,*f2) == true ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test insert_vertex()", ( mesh.insert_vertex(&(pts[4]),*f2) != nil ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test insert_vertex()", ( mesh.vertex_count() == 5 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test insert_vertex()", ( mesh.edge_count() == 16 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test insert_vertex()", ( mesh.face_count() == 4 ) );
	}}

	// Test remove face
	{{
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test remove_face()", ( mesh.remove_face(*f1) == true ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test remove_face()", ( mesh.vertex_count() == 4 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test remove_face()", ( mesh.edge_count() == 12 ) );
		res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test remove_face()", ( mesh.face_count() == 3 ) );
	}}

	// Get number of bytes
	mesh.clear();
	res &= UNIT_TEST_ERROR( "[HalfEdgeTrglMesh] Test memory leak", ( bytes == MemoryManager::instance()->bytes() ));

	// Return result
	return res;
}


#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif
